package com.zhiwei.msf.app.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.RefSpec;
import org.springframework.stereotype.Service;

import com.zhiwei.msf.app.dto.GitCommitLog;
import com.zhiwei.msf.app.service.GitRepositoryService;
import com.zhiwei.msf.common.util.DateUtil;

/**
 * function author zhiwei.yang time 2020-3-4-11:06
 */
@Service
public class GitRepositoryServiceImpl implements GitRepositoryService {

	@Override
	public Git cloneRepository(String repoUrl, String cloneDir, CredentialsProvider provider) throws GitAPIException {
		return Git.cloneRepository().setCredentialsProvider(provider).setURI(repoUrl).setDirectory(new File(cloneDir))
				.call();
	}

	@Override
	public void commitRepository(Git git, String message, CredentialsProvider provider) throws GitAPIException {
		git.add().addFilepattern(".").call();
		git.commit().setMessage(message).call();
	}

	@Override
	public void pushRepository(Git git, CredentialsProvider provider) throws GitAPIException, IOException {
		this.pushRepository(git, null, provider);
	}

	@Override
	public void pushRepository(Git git, String branch, CredentialsProvider provider)
			throws GitAPIException, IOException {
		if (branch == null) {
			// 获取当前分支
			branch = git.getRepository().getBranch();
		}
		git.push().setCredentialsProvider(provider).setRemote("origin").setRefSpecs(new RefSpec(branch)).call();
	}

	@Override
	public Repository getLocalRepository(String localGitDir) throws IOException {
		Git git = getLocalGit(localGitDir);
		return null == git ? null : git.getRepository();
	}

	@Override
	public Git getLocalGit(String localGitDir) throws IOException {
		if (org.apache.commons.lang3.StringUtils.isEmpty(localGitDir)) {
			return null;
		}
		File repositoryDir = new File(localGitDir);
		if (!repositoryDir.exists() || !repositoryDir.isDirectory()) {
			return null;
		}
		return Git.open(repositoryDir);
	}

	@Override
	public List<GitCommitLog> getRepositoryLog(Git git) throws IOException {
		return getSinceCommitRepositoryLog(git, null);
	}

	@Override
	public List<GitCommitLog> getSinceCommitRepositoryLog(Git git, String commitId) throws IOException {
		return getBranchSinceCommitRepositoryLog(git, null, commitId);
	}

	@Override
	public List<GitCommitLog> getBranchSinceCommitRepositoryLog(Git git, String branch, String commitId)
			throws IOException {
		Repository repository = git.getRepository();
		if (null == repository) {
			return Collections.emptyList();
		}
		if (branch == null) {
			branch = repository.getBranch();
		}
		Ref head = repository.findRef("refs/heads/" + branch);
		List<GitCommitLog> commitLogList = new ArrayList<>();
		if (head != null) {
			try (RevWalk revWalk = new RevWalk(repository)) {
				revWalk.markStart(revWalk.parseCommit(head.getObjectId()));
				for (RevCommit revCommit : revWalk) {
					if (revCommit.getId().getName().equals(commitId)) {
						break;
					}
					GitCommitLog gitCommitLog = GitCommitLog.builder().id(revCommit.getId().getName())
							.time(DateUtil.parseDate(revCommit.getCommitTime())).parentCount(revCommit.getParentCount())
							.name(revCommit.getCommitterIdent().getName())
							.email(revCommit.getCommitterIdent().getEmailAddress())
							.msg(revCommit.getFullMessage().replaceAll("[\r\n]", "")).build();
					commitLogList.add(gitCommitLog);
				}
				revWalk.dispose();
			}
		}
		return commitLogList;
	}
}